package kiwi.assist.dev.guieditor.command {
	import fl.core.UIComponent;

	import ghostcat.util.ReflectUtil;

	import kiwi.assist.dev.guieditor.event.GUIEditorEvent;
	import kiwi.assist.dev.guieditor.model.ContainerConfig;
	import kiwi.assist.dev.guieditor.model.PropertyConfig;
	import kiwi.assist.dev.guieditor.model.UiConfig;
	import kiwi.assist.dev.guieditor.model.UiDetailVO;
	import kiwi.assist.dev.guieditor.model.format.BooleanFormat;
	import kiwi.assist.dev.guieditor.model.format.NumericFormat;
	import kiwi.assist.dev.guieditor.model.format.StringFormat;
	import kiwi.assist.dev.util.SkinComponentAdapter;
	import kiwi.debug.Log;
	import kiwi.util.ObjectPool;
	import kiwi.util.sprintf;

	import org.robotlegs.mvcs.Command;

	import flash.display.DisplayObject;
	import flash.events.Event;
	import flash.filesystem.File;
	import flash.filesystem.FileMode;
	import flash.filesystem.FileStream;
	import flash.utils.getQualifiedClassName;

	/**
	 * @author zhangming.luo
	 */
	public class PublishJsCommand extends Command {
		[Inject]
		public var detail : UiDetailVO;
		[Inject]
		public var event : GUIEditorEvent;
		private var noAlert : Boolean;
		private var template : String =/**
		 * 代码的模板采用多行字符串来表达
		 */ 
		<![CDATA[/**
 * ui 界面的表述文件
 */
function ${className}() {
    ${baseContainer}.call(this);
}
$inherits(${className}, ${baseContainer});
${className}.prototype.init = function () {
    // 容器相关的设定
    ${basebody}
    // 背景相关
    ${background}
    // 控件相关
    ${body}
};
]]>;
		private var code : String = "";
		private var basebodyCode : String;
		private var bodyCode : String;
		private var backgroundCode : String;

		override public function execute() : void {
			noAlert = event.data;
			prepare();
			if (detail.container) {
				generateBaseBody();
			} else {
				basebodyCode = "";
			}
			generateBg();
			generateBody();
			merge();
			saveCode();
		}

		/**
		 * 准备一下
		 * 负责类名等相关的事宜
		 */
		private function prepare() : void {
			code = template;
			code = code.replace(/\${packageName}/g, detail.packageName);
			code = code.replace(/\${baseContainer}/g, detail.container.className);
			code = code.replace(/\${className}/g, detail.name);
			bodyCode = "";
			backgroundCode = "";
		}

		/**
		 * 保存代码到文件
		 */
		private function saveCode() : void {
			if (noAlert) {
				var stream : FileStream = new FileStream();
				stream.open(File.applicationDirectory.resolvePath(detail.projectPath + "/" + detail.name + ".js"), FileMode.WRITE);
				stream.writeUTFBytes(code);
				stream.close();
				Log.info("导出完毕 " + detail.fullPath);
				dispatch(new GUIEditorEvent(GUIEditorEvent.PUBLISH_AS_COMPLETE));
			} else {
				var file : File = new File();
				file.addEventListener(Event.COMPLETE, function() : void {
					Log.alert("导出完毕");
					dispatch(new GUIEditorEvent(GUIEditorEvent.PUBLISH_AS_COMPLETE));
				});
				file.save(code, detail.name + ".js");
			}
		}

		private function generateBaseBody() : void {
			basebodyCode = "";
			var impl : DisplayObject = detail.containerImpl;
			var name : String = "super";
			// 基本属性
			basebodyCode += "this.setProps({\n";
			for each (var property:PropertyConfig in detail.container.propertyList) {
				basebodyCode += "    " + getPropertyCode(impl, name, property);
			}
			basebodyCode += '    name: "' + detail.name + '"\n';
			basebodyCode += "});";
		}

		private function generateBg() : void {
			backgroundCode = "";
			var len : int = detail.backgroundSkinList.length;
			var constructor : String;
			var code : String;
			for (var i : int = 0;i < len;i++) {
				constructor = "";
				code = "";
				var skin : SkinComponentAdapter = detail.backgroundSkinList[i];
				var clzName : String = skin.skin.clz ? importClass(skin.skin.clz) : skin.skin.name;
				var name : String;
				if (skin.name.indexOf("instance") == 0 || skin.name == "noname" ) {
					name = "skin";
				} else {
					name = skin.name;
				}
				// 构造
				code += sprintf("ui.newImage({\n");
				// 路径
				code += sprintf("    path: '%s'\n", clzName);
				// 布局
				code += sprintf("    x: %s,\n", skin["dx"]);
				code += sprintf("    y: %s,\n", skin["dy"]);
				code += sprintf("    width: %s,\n", skin.width);
				code += sprintf("    height: %s,\n", skin.height);
				// 添加
				code += sprintf("	name: '%s'\n", "Image");
				code += sprintf("}).addTo(this);\n");
				// 合并
				backgroundCode += code;
				backgroundCode += "\n";
			}
		}

		private function generateBody() : void {
			bodyCode = "";
			var len : int = detail.uiList.length;
			var constructor : String;
			var code : String;
			for (var i : int = 0;i < len;i++) {
				constructor = "";
				code = "";
				var impl : DisplayObject = detail.uiList[i];
				var config : UiConfig = detail.configList[impl];
				if (config is ContainerConfig) {
					// 跳过窗体
					continue;
				}
				var clzName : String;
				if (config.className) {
					clzName = config.className.substring(config.className.lastIndexOf(".") + 1);
				} else {
					clzName = importClass(impl);
				}
				var name : String = impl.name;
				if (!name || name.indexOf("instance") == 0 || name == "noname") {
					// 构造
					constructor = sprintf("ui.newUI(%s, {\n", name, clzName);
				} else {
					// 构造
					constructor = sprintf("this.%s = ui.newUI(%s, {\n", name, clzName);
				}
				var defaultComponent : UIComponent = ObjectPool.allocate(ReflectUtil.getClass(impl));
				// 基本属性
				for each (var property:PropertyConfig in config.propertyList) {
					if (property.key == "x") {
						code += sprintf("    x: %s,\n", impl["dx"]);
					} else if (property.key == "y") {
						code += sprintf("    y: %s,\n", impl["dy"]);
					} else if (property.key == "name") {
						continue;
					} else if (!property.nopublish) {
						if (defaultComponent[property.key] == impl[property.key]) {
							// 如果和默认值一样就导出一个简单的注释
							code += "    " + getCommitCode(getPropertyCode(impl, name, property));
						} else {
							code += "    " + getPropertyCode(impl, name, property);
						}
					}
				}
				code += sprintf("    name: '%s'\n", impl.name);
				code += sprintf("}).addTo(this);\n");

				// 合并
				bodyCode += constructor;
				bodyCode += code;
			}
		}

		private function merge() : void {
			code = replaceCode(code, "${basebody}", basebodyCode);
			code = replaceCode(code, "${background}", backgroundCode);
			code = replaceCode(code, "${body}", bodyCode);
		}

		/**
		 * 保证尽可能正确的还原缩进的
		 */
		private static function replaceCode(code : String, p : String, repl : String) : String {
			if (repl.length == 0) {
				return code.replace(p, "// 没有订制");
			}
			var replList : Array = repl.split("\n");
			if (replList.length <= 1) {
				return code.replace(p, repl);
			}
			var codeList : Array = code.split("\n");
			for (var i : int = 0;i < codeList.length;i++) {
				var line : String = codeList[i];
				var index : int = line.indexOf(p);
				if (index < 0) {
					continue;
				}
				var space : String = line.substr(0, index);
				var suffix : String = line.substr(index + p.length);
				if (space.match(/^\s+/)) {
					// 需要处理缩进的说
					line = "";
					for each (var subLine:String in replList) {
						if (subLine.length == 0) {
							line += "\n";
						} else {
							line += space + subLine + "\n";
						}
					}
					line += suffix;
					codeList[i] = line;
				}
			}
			return codeList.join("\n");
		}

		/**
		 * 生成一个属性的代码
		 */
		private function getPropertyCode(impl : DisplayObject, name : String, property : PropertyConfig) : String {
			if (property.nopublish) {
				// 不发布的代码
				return "";
			}
			var code : String = "";
			var value : String;
			if (property.format is BooleanFormat) {
				value = impl[property.key] ? "true" : "false";
			} else if (property.format is NumericFormat) {
				value = impl[property.key];
			} else if (property.format is StringFormat) {
				if (impl[property.key] == "null" || impl[property.key] == null) {
					// Pass
					return "";
				} else {
					value = sprintf("\"%s\"", impl[property.key]);
				}
			}
			code += sprintf("%s: %s,\n", property.key, value);
			return code;
		}

		private function importClass(clz : *, fullName : Boolean = false) : String {
			clz = ReflectUtil.getClass(clz);
			var name : String = getQualifiedClassName(clz);
			if (fullName) {
				return name.replace("::", ".");
			}
			var index : int = name.indexOf("::");
			if (index >= 0) {
				return name.substring(name.indexOf("::") + 2);
			}
			return name;
		}

		/**
		 * 获取注释版本的代码
		 */
		private function getCommitCode(code : String) : String {
			return code.replace(/^(.)/g, "// $1");
		}
	}
}
